package com.ctvit.breadking.news.xfyun.service.impl;

import com.ctvit.breadking.news.core.solr.repository.SolrDocumentRepository;
import com.ctvit.breadking.news.task.pojo.entity.HttpLogEntity;
import com.ctvit.breadking.news.xfyun.service.GlobalTranslationService;
import com.ctvit.breadking.news.xfyun.util.HttpUtil;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.solr.common.SolrInputDocument;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Service;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;

import static com.ctvit.breadking.news.core.constant.CommonConstant.FIELD_CREATE_TIME;

@Slf4j
@Service
public class GlobalTranslationServiceImpl implements GlobalTranslationService {

    private static final String WebITS_URL = "https://its-api-sg.xf-yun.com/v2/its";
    // Access from the Console to find Machine Translation
    private static final String APPID = "ga4da75f";
    // Access from the Console to find Machine Translation
    private static final String API_KEY = "0b359aaa6cc91834f32b079de592c5b1";
    // Access from the Console to find Machine Translation
    private static final String API_SECRET = "e61236b5a84da2e04e6030fc84e56a86";
    // Source language
    private static final String FROM = "en";
    // Target language
    private static final String TO = "cn";

    private final SolrDocumentRepository solrDocumentRepository;

    public GlobalTranslationServiceImpl(SolrDocumentRepository solrDocumentRepository) {
        this.solrDocumentRepository = solrDocumentRepository;
    }

    @Override
    public boolean translate(String text) throws Exception {
        String requestBody = buildHttpBody(text);
        log.info("【ITSWebAPI body】\n" + requestBody);
        Map<String, String> header = buildHttpHeader(requestBody);
        long requestTime = System.currentTimeMillis();
        Map<String, Object> resultMap = HttpUtil.doPost2(WebITS_URL, header, requestBody);
        long responseTime = System.currentTimeMillis();

        log.info("its-api-sg.duration:[{}]", (responseTime - requestTime));

        String responseBody = "";
        if (resultMap != null) {
            responseBody = resultMap.get("body").toString();
            log.info("【its result】\n" + responseBody);

            Gson json = new Gson();
            ResponseData resultData = json.fromJson(responseBody, ResponseData.class);
            int code = resultData.getCode();
            if (code != 0) {
                log.error("Please follow the error message tips to handle");
            } else {
                SolrInputDocument solrDocument = assignHttpLogElement(HttpMethod.POST.name(), requestBody, responseBody, requestTime, responseTime);
                solrDocumentRepository.add(HttpLogEntity.COLLECTION_HTTP_LOG, solrDocument.getFieldValue(HttpLogEntity.FIELD_ID).toString(), solrDocument);
                return true;
            }
        } else {
            log.error("Please follow the error message tips to handle");
        }
        return false;
    }

    private SolrInputDocument assignHttpLogElement(String requestMethod, String requestBody, String responseBody, long requestTime, long responseTime) {
        SolrInputDocument solrDocument = new SolrInputDocument();
        solrDocument.addField(HttpLogEntity.FIELD_ID, "its-api-sg.xf-yun.com/v2/its_" + System.currentTimeMillis());
        solrDocument.addField(HttpLogEntity.FIELD_CODE, "its-api-sg.xf-yun.com/v2/its");
        solrDocument.addField(HttpLogEntity.FIELD_NAME, "科大讯飞机器翻译-海外");
        solrDocument.addField(HttpLogEntity.FIELD_URL, WebITS_URL);
        solrDocument.addField(HttpLogEntity.FIELD_REQUEST_METHOD, requestMethod);
        solrDocument.addField(HttpLogEntity.FIELD_REQUEST_BODY, requestBody);
        solrDocument.addField(HttpLogEntity.FIELD_REQUEST_TIME, requestTime);
        solrDocument.addField(HttpLogEntity.FIELD_RESPONSE_BODY, responseBody);
        solrDocument.addField(HttpLogEntity.FIELD_RESPONSE_TIME, responseTime);
        solrDocument.addField(FIELD_CREATE_TIME, new Date());
        return solrDocument;
    }

    public static Map<String, String> buildHttpHeader(String body) throws Exception {
        Map<String, String> header = new HashMap<String, String>();
        URL url = new URL(WebITS_URL);

        //Generating a timestamp in RFC1123 format
        SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
        format.setTimeZone(TimeZone.getTimeZone("GMT"));
        Date dateD = new Date();
        String date = format.format(dateD);
        //System.out.println("【ITS WebAPI date】\n" + date);

        String digestBase64 = "SHA-256=" + signBody(body);
        //System.out.println("【ITS WebAPI digestBase64】\n" + digestBase64);

        StringBuilder builder = new StringBuilder("host: ").append(url.getHost()).append("\n").//
                append("date: ").append(date).append("\n").//
                append("POST ").append(url.getPath()).append(" HTTP/1.1").append("\n").//
                append("digest: ").append(digestBase64);
        //System.out.println("【ITS WebAPI builder】\n" + builder);
        String sha = hmacsign(builder.toString(), API_SECRET);
        //System.out.println("【ITS WebAPI sha】\n" + sha);

        String authorization = String.format("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"", API_KEY, "hmac-sha256", "host date request-line digest", sha);
        System.out.println("【ITS WebAPI authorization】\n" + authorization);

        header.put("Authorization", authorization);
        header.put("Content-Type", "application/json");
        header.put("Accept", "application/json,version=1.0");
        header.put("Host", url.getHost());
        header.put("Date", date);
        header.put("Digest", digestBase64);
        System.out.println("【ITS WebAPI header】\n" + header);
        return header;
    }

    public static String buildHttpBody(String text) throws Exception {
        JsonObject body = new JsonObject();
        JsonObject business = new JsonObject();
        JsonObject common = new JsonObject();
        JsonObject data = new JsonObject();
        //common
        common.addProperty("app_id", APPID);
        //business
        business.addProperty("from", FROM);
        business.addProperty("to", TO);
        //data
        byte[] textByte = text.getBytes("UTF-8");
        String textBase64 = new String(Base64.getEncoder().encodeToString(textByte));
        data.addProperty("text", textBase64);
        //body
        body.add("common", common);
        body.add("business", business);
        body.add("data", data);
        return body.toString();
    }

    private static String signBody(String body) throws Exception {
        MessageDigest messageDigest;
        String encodestr = "";
        try {
            messageDigest = MessageDigest.getInstance("SHA-256");
            messageDigest.update(body.getBytes("UTF-8"));
            encodestr = Base64.getEncoder().encodeToString(messageDigest.digest());
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return encodestr;
    }
    private static String hmacsign(String signature, String apiSecret) throws Exception {
        Charset charset = Charset.forName("UTF-8");
        Mac mac = Mac.getInstance("hmacsha256");
        SecretKeySpec spec = new SecretKeySpec(apiSecret.getBytes(charset), "hmacsha256");
        mac.init(spec);
        byte[] hexDigits = mac.doFinal(signature.getBytes(charset));
        return Base64.getEncoder().encodeToString(hexDigits);
    }

    public static class ResponseData {
        private int code;
        private String message;
        private String sid;
        private Object data;
        public int getCode() {
            return code;
        }
        public String getMessage() {
            return this.message;
        }
        public String getSid() {
            return sid;
        }
        public Object getData() {
            return data;
        }
    }

}
